Dynomotion

Group: DynoMotion Message: 11772 From: Hardy Family Date: 6/24/2015
Subject: Random extra delays with MoveAtVel()/CheckDone()
We are experiencing some strange behavior on the kflop (433L).  There is a touch probing routine which is invoked with M100.  The routine performs some linear moves using a roughly coordinated movement of 3 linear axes (the start_move() function below).  Then there is a loop which checks for completion of the move.

What we are seeing is that there is the occasional delay in the move_done() loop, which lasts well beyond the time the axes appear to complete the move.  For example, in our probing routine the typical move is about 20mm, which normally takes about 0.5 sec.  The delays occur about 1 time in 10, and the additional delay time ranges from 0 to about 6 seconds.

It is not that CheckDone() is taking a long time to return, but it is reporting "not done" for some time after the move has actually completed.

Our system has 3 threads running at this point: a background supervisor, the probing routine itself, and another thread which is used to launch the probe and wait for the result.  By counting the number of loops, it can be verified that the loop period is 360us, as expected, so I don't think it is anything else in our code which is blocking the CPU etc.

Basically, the code works and returns the correct results, but the extra delays are annoying.  My colleague speculates that the machine is "thinking about doing something naughty" :-)

Do you have any insight into why this would be happening?

Regards,
SJH

This is a somewhat simplified outline of the code...

/*
    Start a "coordinated" move.
*/
int start_move(double x, double y, double z, double vel, int rel)
{
    double dx = rel ? x : x - chan[0].Position;
    double dy = rel ? y : y - chan[1].Position;
    double dz = rel ? z : z - chan[2].Position;
    double r = sqrt(dx*dx+dy*dy+dz*dz);
   
    if (rel) {
        x += chan[0].Position;
        y += chan[1].Position;
        z += chan[2].Position;
    }
    vel /= r;
    MoveAtVel(0, x, vel*fast_fabs(dx));
    MoveAtVel(1, y, vel*fast_fabs(dy));
    MoveAtVel(2, z, vel*fast_fabs(dz));
    return 0;
}



int move_done(void)
{
    return CheckDone(1) && CheckDone(2) && CheckDone(0);
}

...

    while (!move_done()) {
        WaitNextTimeSlice();
    }


Group: DynoMotion Message: 11790 From: Tom Kerekes Date: 6/26/2015
Subject: Re: Random extra delays with MoveAtVel()/CheckDone()
Hi SJH,

I think this might be a bug in the KFLOP Firmware.  Please try the patch described here:


Regards
TK
 

Group: DynoMotion Message: 11812 From: Hardy Family Date: 6/28/2015
Subject: Re: Random extra delays with MoveAtVel()/CheckDone()
Hi Tom,

I flashed the 433m firmware, but unfortunately the pauses are still there.  If anything, they are a bit more frequent now, but admittedly I haven't tested it very extensively.

At present, we have a work-around in the following function, but it would be nice to root out the real cause.

mdest is a vector that the code maintains for the "target point" of the move, and 'moving' is a boolean set when we are moving to a new dest.

int move_done(void)
{
    double dx, dy, dz, r2;
    // FIXME: for a reason TBD, CheckDone() is not reporting move completion for
    // a random time interval 0-6 sec past actual move completion.
    // So we work around by comparing current position to mdest.
    if (CheckDone(1) && CheckDone(2) && CheckDone(0)) {
        //printf("move_done: CheckDone() ok\n");
        return 1;
    }
  #if WORKAROUND
    if (moving) {
        dx = chan[0].Position - mdest[0];
        dy = chan[1].Position - mdest[1];
        dz = chan[2].Position - mdest[2];
        r2 = dx*dx+dy*dy+dz*dz;
        // When probing, we are never really interested in getting to an exact
        // location, so it is appropriate to declare 'done' when we are within
        // 0.1mm of dest.
        if (r2 < 10000.) {
            //printf("move_done: near enough\n");
            return 1;
        }
    }
  #endif
    return 0;
}



Regards,
SJH


On Fri, Jun 26, 2015 at 7:14 PM, Tom Kerekes tk@... [DynoMotion] <DynoMotion@yahoogroups.com> wrote:
 

Hi SJH,

I think this might be a bug in the KFLOP Firmware.  Please try the patch described here:


Regards
TK
 

Group: DynoMotion Message: 11813 From: Tom Kerekes Date: 6/28/2015
Subject: Re: Random extra delays with MoveAtVel()/CheckDone()
Hi SJH,

Hmmmm.  I do have a concern about your start_move routine.  It commands all 3 axes to move regardless of whether all the axes really need to move or not.  It also is using measured "Position" rather than Commanded "Dest" which will contain servo dither error and encoder quantization error.  It is also calculating the Vel based on the distance it thinks it need to move the axis.  So I worry that due to small errors (including floating point round off as well) it may decide it needs to move an infinitesimal distance at an infinitesimal velocity resulting in an indeterminate amount time.

Actually thinking about it further I'm thinking it mainly has to do with Position/Destination issues.  The Move trajectory will be computed based on starting from the last commanded Destination.  But your specified velocity is computed based on the last measured position. 

So for example, assume:

Last Destination = 1000
Current measured Position = 1001 (due to +/- 1 count servo dither)
MoveTo = 1001.1

In this case your velocity will be based on an expected move of only 0.1, but this will be used for a motion of 1.1 so it will take 11X longer than expected.

You might try replacing your Position references with Dest references.  You also may want to check for very small move distance (ie less than 1 microstep) and in that case either don't move at all or set the velocity to something like 1000.0 to immediately do the motion in 1ms.

HTH
Regards
TK






Group: DynoMotion Message: 11814 From: Hardy Family Date: 6/28/2015
Subject: Re: Random extra delays with MoveAtVel()/CheckDone()
Yes, that explanation makes sense.  As it happens, the pauses occur on moves which are axis aligned, so there would be numeric instability there (approaching 0/0).  So I have modified to use all Dest and not move axes less than 1 step.  Will give it a try soon...

I should have tried printing axis positions during the pauses - that would have immediately showed it up.  Hindsight.

Regards,
SJH


On Sun, Jun 28, 2015 at 1:22 PM, Tom Kerekes tk@... [DynoMotion] <DynoMotion@yahoogroups.com> wrote:
 

Hi SJH,

Hmmmm.  I do have a concern about your start_move routine.  It commands all 3 axes to move regardless of whether all the axes really need to move or not.  It also is using measured "Position" rather than Commanded "Dest" which will contain servo dither error and encoder quantization error.  It is also calculating the Vel based on the distance it thinks it need to move the axis.  So I worry that due to small errors (including floating point round off as well) it may decide it needs to move an infinitesimal distance at an infinitesimal velocity resulting in an indeterminate amount time.

Actually thinking about it further I'm thinking it mainly has to do with Position/Destination issues.  The Move trajectory will be computed based on starting from the last commanded Destination.  But your specified velocity is computed based on the last measured position. 

So for example, assume:

Last Destination = 1000
Current measured Position = 1001 (due to +/- 1 count servo dither)
MoveTo = 1001.1

In this case your velocity will be based on an expected move of only 0.1, but this will be used for a motion of 1.1 so it will take 11X longer than expected.

You might try replacing your Position references with Dest references.  You also may want to check for very small move distance (ie less than 1 microstep) and in that case either don't move at all or set the velocity to something like 1000.0 to immediately do the motion in 1ms.

HTH
Regards
TK






Group: DynoMotion Message: 11818 From: Hardy Family Date: 6/28/2015
Subject: Re: Random extra delays with MoveAtVel()/CheckDone()

OK problem solved. It was my code after all. Although if it helped you find another issue then it wasn't a total waste of time :-)

Regards,
Sjh

On Jun 28, 2015 2:11 PM, "Hardy Family" <hardy.woodland.cypress@...> wrote:
Yes, that explanation makes sense.  As it happens, the pauses occur on moves which are axis aligned, so there would be numeric instability there (approaching 0/0).  So I have modified to use all Dest and not move axes less than 1 step.  Will give it a try soon...

I should have tried printing axis positions during the pauses - that would have immediately showed it up.  Hindsight.

Regards,
SJH


On Sun, Jun 28, 2015 at 1:22 PM, Tom Kerekes tk@... [DynoMotion] <DynoMotion@yahoogroups.com> wrote:
 

Hi SJH,

Hmmmm.  I do have a concern about your start_move routine.  It commands all 3 axes to move regardless of whether all the axes really need to move or not.  It also is using measured "Position" rather than Commanded "Dest" which will contain servo dither error and encoder quantization error.  It is also calculating the Vel based on the distance it thinks it need to move the axis.  So I worry that due to small errors (including floating point round off as well) it may decide it needs to move an infinitesimal distance at an infinitesimal velocity resulting in an indeterminate amount time.

Actually thinking about it further I'm thinking it mainly has to do with Position/Destination issues.  The Move trajectory will be computed based on starting from the last commanded Destination.  But your specified velocity is computed based on the last measured position. 

So for example, assume:

Last Destination = 1000
Current measured Position = 1001 (due to +/- 1 count servo dither)
MoveTo = 1001.1

In this case your velocity will be based on an expected move of only 0.1, but this will be used for a motion of 1.1 so it will take 11X longer than expected.

You might try replacing your Position references with Dest references.  You also may want to check for very small move distance (ie less than 1 microstep) and in that case either don't move at all or set the velocity to something like 1000.0 to immediately do the motion in 1ms.

HTH
Regards
TK